/*
 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_SHARING_RTMP_PROTOCOL_H
#define OHOS_SHARING_RTMP_PROTOCOL_H

#include <cstdio>
#include <functional>
#include <unordered_map>
#include "data_buffer.h"
#include "rtmp_common.h"

#define DATA_CHUNK_SIZE_OUT 60000

namespace OHOS {
namespace Sharing {

class RtmpProtocol {
public:
    using Ptr = std::shared_ptr<RtmpProtocol>;
    using DataCallBack = std::function<void(const char *, size_t)>;

    RtmpProtocol();
    virtual ~RtmpProtocol();

    void StartClientSession(const std::function<void()> &cb);

    virtual void Send(const char *buf, int len) = 0;
    static void SendRtmp(RTMPMessageType type, uint32_t streamIndex, const std::string &buffer, uint32_t stamp,
                         int chunk_id, DataCallBack callback);
    static void SendRtmp(RTMPMessageType type, uint32_t streamIndex, const DataBuffer::Ptr &buffer, uint32_t stamp,
                         int chunk_id, DataCallBack callback);

protected:
    void Reset();

    void SendChunkSize(uint32_t size);
    void SendPeerBandwidth(uint32_t size);
    void SendAcknowledgement(uint32_t size);
    void SendAcknowledgementSize(uint32_t size);
    void SendPingRequest(uint32_t ti = ::time(nullptr));
    void SendPingResponse(uint32_t timestamp = ::time(nullptr));
    void SendSetBufferLength(uint32_t streamIndex, uint32_t len);
    void SendUserControl(uint16_t eventType, uint32_t eventData);
    void SendInvoke(const std::string &cmd, const AmfValue &val);
    void SendRequest(RTMPMessageType cmd, const std::string &str);
    void SendResponse(RTMPMessageType type, const std::string &str);
    void SendUserControl(uint16_t eventType, const std::string &eventData);

    virtual void OnStreamEof(uint32_t streamIndex){};
    virtual void OnStreamDry(uint32_t streamIndex){};
    virtual void OnRtmpChunk(RtmpPacket::Ptr chunk_data) = 0;

    virtual void OnStreamBegin(uint32_t streamIndex)
    {
        streamIndex_ = streamIndex;
    }

private:
    void HandleRtmpChunk(RtmpPacket::Ptr chunk_data);
    const char *HandleRtmp(const char *data, size_t len);
    const char *HandleS0S1S2(const char *data, size_t len, const std::function<void()> &func);

protected:
    int sendReqId_ = 0;
    int nowStreamIndex_ = 0;
    uint32_t streamIndex_ = STREAM_CONTROL;
    std::function<const char *(const char *data, size_t len)> nextStepFunc_;
    std::unordered_map<int, std::pair<RtmpPacket::Ptr /*now*/, RtmpPacket::Ptr /*last*/>> mapChunkData_;

private:
    bool dataStarted_ = false;
    uint8_t bandLimitType_ = 2;

    int nowChunkId_ = 0;
    uint32_t windowsSize_ = 0;
    uint32_t bandwidth_ = 2500000;

    uint64_t bytesSent_ = 0;
    uint64_t bytesRecv_ = 0;
    uint64_t bytesSentLast_ = 0;
    uint64_t bytesRecvLast_ = 0;

    size_t chunkSizeIn_ = DEFAULT_CHUNK_LEN;
    size_t chunkSizeOut_ = DEFAULT_CHUNK_LEN;

    DataBuffer::Ptr cache_ = nullptr;
};
} // namespace Sharing
} // namespace OHOS

#endif // OHOS_SHARING_RTMP_PROTOCOL_H
